package cn.com.cetccst.mdmdemo.utils;

import android.text.TextUtils;
import android.util.Log;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ReflectHelper {

    private static final String TAG = "ReflectHelper";
    private static final String APK_SUPPORT_CLASS = "com.android.mms.SmartSupportUtils";

    /**
     * Get the class object for the first constructor, if need use the other constructors, should
     * not use this method.
     *
     * @param className
     * @param args
     * @return
     */
    public static Object getClassObject(String className, Object... args) {
        if (TextUtils.isEmpty(className)) {
            Log.e(TAG, "ReflectHelper getClassObject className is null");
            return null;
        }
        Object container = null;
        try {
            Class c = Class.forName(className);
            Constructor constructors[] = c.getDeclaredConstructors();
            Constructor constructor = constructors[0];
            constructor.setAccessible(true);
            container = constructor.newInstance(args);
        } catch (ClassNotFoundException e) {
            Log.d(TAG, "ClassNotFoundException when get class object : ", e);
        } catch (IllegalAccessException e) {
            Log.d(TAG, "IllegalAccessException when get class object : ", e);
        } catch (InstantiationException e) {
            Log.d(TAG, "InstantiationException when get class object : ", e);
        } catch (InvocationTargetException e) {
            Log.d(TAG, "InvocationTargetException when get class object : ", e);
        }
        return container;
    }

    public static Object callReflectMethod(Object container, String methodName, Class[] argTypes, Object[] args) {
        /* AR0009LD0M xiaoyuan/lwx323819 20171120 begin */
        if (container == null || TextUtils.isEmpty(methodName)) {
            Log.e(TAG, "ReflectHelper callReflectMethod container is null or methodName is null");
            return null;
        }
        /* AR0009LD0M xiaoyuan/lwx323819 20171120 end */
        Object object = null;
        try {
            Method method = container.getClass().getDeclaredMethod(methodName, argTypes);
            method.setAccessible(true);
            object = method.invoke(container, args);
        } catch (NoSuchMethodException e) {
            Log.d(TAG, "NoSuchMethodException when call reflect method : ", e);
        } catch (IllegalAccessException e) {
            Log.d(TAG, "IllegalAccessException when call reflect method : ", e);
        } catch (InvocationTargetException e) {
            Log.d(TAG, "InvocationTargetException when call reflect method : ", e);
        }
        return object;
    }

    public static Object callReflectStaticMethod(String className, String methodName, Class[] argTypes, Object[] args) {
        if (TextUtils.isEmpty(className) || TextUtils.isEmpty(methodName)) {
            Log.e(TAG, "ReflectHelper callReflectStaticMethod className is null or methodName is null");
            return null;
        }
        Object result = null;
        try {
            Class<?> threadClazz = Class.forName(className);
            Method method = threadClazz.getMethod(methodName, argTypes);
            result = method.invoke(null, args);
        } catch (ClassNotFoundException e) {
            Log.d(TAG, "ClassNotFoundException when call reflect static method : ", e);
        } catch (NoSuchMethodException e) {
            Log.d(TAG, "NoSuchMethodException when call reflect static method : ", e);
        } catch (IllegalAccessException e) {
            Log.d(TAG, "IllegalAccessException when call reflect static method : ", e);
        } catch (InvocationTargetException e) {
            Log.d(TAG, "InvocationTargetException when call reflect static method : ", e);
        }
        return result;
    }

    public static Object getReflectStaticField(String className, String fieldName) {
        if (TextUtils.isEmpty(className) || TextUtils.isEmpty(fieldName)) {
            Log.e(TAG, "ReflectHelper getReflectStaticField className is null or fieldName is null");
            return null;
        }
        Object result = null;
        try {
            Class<?> threadClazz = Class.forName(className);
            Field field = threadClazz.getDeclaredField(fieldName);
            result = field.get(threadClazz);
        } catch (ClassNotFoundException e) {
            Log.d(TAG, "ClassNotFoundException when reflect static field : ", e);
        } catch (NoSuchFieldException e) {
            Log.d(TAG, "NoSuchFieldException when reflect static field : ", e);
        } catch (IllegalAccessException e) {
            Log.d(TAG, "IllegalAccessException when reflect static field : ", e);
        }
        return result;
    }

    public static Object getReflectField(Object container, String fieldName) {
        if (container == null || TextUtils.isEmpty(fieldName)) {
            Log.e(TAG, "ReflectHelper getReflectField container is null or fieldName is null");
            return null;
        }
        Object object = null;
        try {
            Field field = container.getClass().getDeclaredField(fieldName);
            object = field.get(container);
        } catch (NoSuchFieldException e) {
            Log.d(TAG, "NoSuchFieldException when reflect field : ", e);
        } catch (IllegalAccessException e) {
            Log.d(TAG, "IllegalAccessException when reflect field : ", e);
        }
        return object;
    }

    public static boolean getApkIsSupportSmartSms() {
        try {
            Class<?> threadClazz = Class.forName(APK_SUPPORT_CLASS);
            if (threadClazz != null) {
                return true;
            }
        } catch (ClassNotFoundException e) {
            Log.d(TAG, "ClassNotFoundException when reflect static field : ", e);
        }
        return false;
    }

    /**
     * Calling a method or a super class method by reflection.
     * if do not have {@methodName} method in class or super class, return null.
     */
    public static Object callSuperClassReflectMethod(Object container, String methodName,
                                                     Class[] argTypes, Object[] args) {
        if (container == null || TextUtils.isEmpty(methodName)) {
            Log.e(TAG, "ReflectHelper callSuperClassReflectMethod container is null or methodName is null");
            return null;
        }
        Object object = null;
        try {
            Method method = getMethodOrSuperMethod(container.getClass(), methodName, argTypes);
            if (method != null) {
                method.setAccessible(true);
                object = method.invoke(container, args);
            }
        } catch (IllegalAccessException e) {
            Log.d(TAG, "callSuperClassReflectMethod IllegalAccessException when call reflect method : ", e);
        } catch (InvocationTargetException e) {
            Log.d(TAG, "callSuperClassReflectMethod InvocationTargetException when call reflect method : ", e);
        }
        return object;
    }

    private static Method getMethodOrSuperMethod(Class clazz, String methodName, Class[] argTypes) {
        if (clazz == null || TextUtils.isEmpty(methodName)) {
            Log.e(TAG, "ReflectHelper getSuperMethod object is null or methodName is null");
            return null;
        }
        Method method = null;
        try {
            method = clazz.getDeclaredMethod(methodName, argTypes);
        } catch (NoSuchMethodException e) {
            if (clazz.getSuperclass() == null) {
                return method;
            }
            method = getMethodOrSuperMethod(clazz.getSuperclass(), methodName, argTypes);
        }
        return method;
    }
}
